#include "BackupFSCore.h"
#include <filesystem>
#include "../logger/BackupFSLogger.h"
#include "BackupFSUtils.h"
#include "BackupFSSql.h"
namespace fs = std::filesystem;

using namespace std;
namespace BackupFS
{
	BackupFSCore* BackupFSCore::_Instance = nullptr;
	std::mutex BackupFSCore::_Locker;
	std::atomic<LONGLONG> BackupFSCore::FsInodeNumber = 1;
	std::atomic<LONGLONG> BackupFSCore::DataBlockId = 1;

	BackupFSCore::BackupFSCore()
	{
		_FileHeader.BlockSize = BACKUPFS_PAGE_SIZE;
		_FileHeader.DataOffset = BACKUPFS_PAGE_SIZE;
		_FileHeader.FileType = DATA_TYPE;
		_FileHeader.Version = 1;
		memset(_FileHeader.Magic, 0, sizeof(_FileHeader.Magic));
		memcpy(_FileHeader.Magic, BACKUPFS_MAGIC, strlen(BACKUPFS_MAGIC));
		_StartTickCount = GetTickCount64();
		_StartTime = time(NULL);
	}
	BackupFSCore::~BackupFSCore()
	{

	}
	/*
	Get start time,for performance,not use time(NULL) to get the current time
	*/
	void BackupFSCore::GetStartTime(LONGLONG& start_time, LONGLONG& start_tickcount)
	{
		start_time = _StartTime;
		start_tickcount = _StartTickCount;
	}
	std::wstring BackupFSCore::_GetExtName(FILE_SYSTEM_MODE mode)
	{
		switch (mode)
		{
		case  FILE_SYSTEM_MODE::DRILL_MODE:
			return L".DRILL";
		case FILE_SYSTEM_MODE::INCREMENTAL_MODE:
			return L".INC";
		}
		return L"";
	}
	bool BackupFSCore::Init(const std::wstring& data_path,LONGLONG fs_size, bool& has_db)
	{
		_DataPath = data_path;
		_UsedSize = 0;
		_ReadOnly = false;
		if (fs_size != 0)
		{
			_FsSize = fs_size;
		}
		_DataFile = _DataPath + BACK_SLASH + DATA_FILE;
		_DbFile = _DataPath + BACK_SLASH + BAKUPFS_DB_FILE;
		_FlagFile = _DataPath + BACK_SLASH + BAKUPFS_FLAG_FILE;
		//for the drill or incremental modes,prepare the needed files
		if (_Mode != FILE_SYSTEM_MODE::NORMAL_MODE)
		{
			_BaseDataFile = _DataFile;
			_DataFile = _DataPath + BACK_SLASH + DATA_FILE + _GetExtName(_Mode);
			_DbFile = _DataPath + BACK_SLASH + BAKUPFS_DB_FILE + _GetExtName(_Mode);
			_FlagFile = _DataPath + BACK_SLASH + BAKUPFS_FLAG_FILE + _GetExtName(_Mode);
			_BitmapFile = _DataPath + BACK_SLASH + BITMAP_FILE + _GetExtName(_Mode);
			/*
			For the incremental mode and the bitmap file does exist,read it
			*/
			if (_Mode == FILE_SYSTEM_MODE::INCREMENTAL_MODE and std::filesystem::exists(_BitmapFile))
			{
				if (_HandleBitmap == INVALID_HANDLE_VALUE)
				{
					_HandleBitmap = CreateFile(_BitmapFile.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
					if (_HandleBitmap == INVALID_HANDLE_VALUE)
					{
						Logger->Error("Open Bitmap file failed,the error is ", GetLastError());
						return false;
					}
					//read the bitmap file information
					while (true)
					{
						DWORD read_size = 0;
						LONGLONG group_index = 0;
						if (!ReadFile(_HandleBitmap, &group_index, sizeof(group_index), &read_size, NULL))
						{
							return false;
						}
						if (read_size < sizeof(group_index))
						{
							break;
						}
						//construct the bitmap information
						std::shared_ptr<BackupFSBitmap> bitmap = std::make_shared<BackupFSBitmap>(_DataPath,true, group_index);
						_IncrementalBitmap[group_index] = bitmap;
					}
				}
			}
			/*
			If the mode is DRILL and the data file existed, then remove it firstly.
			*/
			if (_Mode == FILE_SYSTEM_MODE::DRILL_MODE && std::filesystem::exists(_DbFile))
			{
				std::filesystem::remove(_DbFile);
			}
			std::wstring base_db_file = _DataPath + BACK_SLASH + BAKUPFS_DB_FILE;
			if (std::filesystem::exists(base_db_file))
			{
				//For drill mode,copy the db file,
				//But for incremental mode,If the db file existed, just re-use it
				bool need_copy = true;
				if (_Mode == FILE_SYSTEM_MODE::INCREMENTAL_MODE)
				{
					if (std::filesystem::exists(_DbFile))
					{
						need_copy = false;
					}
				}
				if (need_copy)
				{
					std::filesystem::copy_file(base_db_file, _DbFile);
				}
			}
			else
			{
				Logger->Error("Start drill mdoe failed, there is no file system");
				return false;
			}
		}
		if (!_FsDb.Init(_DbFile,has_db))
		{
			return false;
		}
		FS_INFO fsinfo = { 0 };
		BackupFSSql::GetFsInfo(BackupFSCore::GetInstance()->GetDb(), fsinfo);
		BackupFSCore::FsInodeNumber = fsinfo.CurrentNodeId;
		BackupFSCore::DataBlockId = fsinfo.CurrentBlockId;
		if (fsinfo.Size != 0)
		{
			SetFsSize(fsinfo.Size);
		}
		else if (fs_size != 0)
		{
			SetFsSize(fs_size);
			BackupFSSql::UpdateCurrentFSSize(BackupFSCore::GetInstance()->GetDb(), fs_size);
		}
		if (fsinfo.UsedSize != 0)
		{
			AddUsedSize(fsinfo.UsedSize);
		}

		if (!_OpenCoreFiles())
		{
			return false;
		}
		return true;
		
	}
	void BackupFSCore::SetFsSize(LONGLONG size)
	{ 
		_FsSize = size; 
		if (_FsSize > _UsedSize)
		{
			_FsSize.store(_FsSize);
		}
	}
	/*
	Set the sparse range for the offset and length
	*/
	bool BackupFSCore::_SetSparseRange(HANDLE hFile, LONGLONG fileOffset, LONGLONG length)
	{
		FILE_ZERO_DATA_INFORMATION zeroDataInfo = { 0 };
		zeroDataInfo.FileOffset.QuadPart = fileOffset;
		zeroDataInfo.BeyondFinalZero.QuadPart = fileOffset + length;
		DWORD bytesReturned;
		return DeviceIoControl(hFile, FSCTL_SET_ZERO_DATA, &zeroDataInfo, sizeof(zeroDataInfo), NULL, 0, &bytesReturned, NULL);
	}
	LONGLONG BackupFSCore::GetFreeSize()
	{ 
		if (_FsSize > _UsedSize)
		{
			return _FsSize - _UsedSize;
		}
		return 0;
	}
	LONGLONG BackupFSCore::AddUsedSize(LONGLONG used_size)
	{ 
		_UsedSize += used_size; 
		return _UsedSize;
	}
	LONGLONG BackupFSCore::ReadForIncremental(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset)
	{	
		//*
		LONGLONG group_index = offset / BACKUPFS_BITMAP_GROUP_SIZE;
		LONGLONG group_index2 = (offset + bufferlength) / BACKUPFS_BITMAP_GROUP_SIZE;
		LONGLONG total_length = bufferlength;
		LONGLONG group_offset = offset;
		LONGLONG total_read_size = 0;
		//group by group
		for (LONGLONG idx = group_index; idx <= group_index2; idx++)
		{
			LONGLONG group_length = total_length;
			//beyond the group,adjust the group_length
			//check the group_length and offset whether exceed the group bound
			if ((total_length + group_offset) > (idx + 1) * BACKUPFS_BITMAP_GROUP_SIZE)
			{
				group_length = (idx + 1) * BACKUPFS_BITMAP_GROUP_SIZE - group_offset;
			}
			if (group_length > total_length)
			{
				group_length = total_length;
			}
			//Divide the blocks by length, each block is 4K, 
			//the first and last blocks may be less than 4K
			LONGLONG read_size = 0;
			for (; read_size < group_length;)
			{
				bool is_in_bitmap = false;
				if (_IncrementalBitmap.find(idx) != _IncrementalBitmap.end())
				{
					auto bitmap = _IncrementalBitmap[idx];
					if (bitmap->IsSet(group_offset % BACKUPFS_BITMAP_GROUP_SIZE))
					{
						is_in_bitmap = true;
					}
				}
				LONGLONG need_read_size = BACKUPFS_PAGE_SIZE;
				LONGLONG block_offset = group_offset / BACKUPFS_PAGE_SIZE * BACKUPFS_PAGE_SIZE;
				if (group_offset % BACKUPFS_PAGE_SIZE != 0)
				{
					need_read_size = BACKUPFS_PAGE_SIZE - group_offset % BACKUPFS_PAGE_SIZE;
				}
				if (need_read_size > group_length - read_size)
				{
					need_read_size = group_length - read_size;
				}
				LONGLONG temp_read_size = 0;
				//read the data from base data or current data file
				if (!BackupFSUtils::ReadFileData(is_in_bitmap ? _HandleDataFile : _HandleBaseDataFile, (char*)buffer + total_read_size, group_offset, need_read_size, temp_read_size))
				{
					return 0;
				}
				read_size += temp_read_size;
				total_read_size += temp_read_size;
				group_offset += temp_read_size;
				total_length -= temp_read_size;
				if (total_read_size >= bufferlength)
				{
					break;
				}
			}

		}
		return total_read_size;
		//*/
	}
	LONGLONG BackupFSCore::ReadNormal(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset)
	{
		//Read for normal mode
		if (!BackupFSUtils::Seek(_HandleDataFile, offset))
		{
			Logger->Error("seek file to pos ", offset, " failed:", GetLastError());
			return 0;
		}
		DWORD read_size = 0;
		if (!ReadFile(_HandleDataFile, buffer, (DWORD)bufferlength, &read_size, NULL))
		{
			Logger->Error("read file from pos ", offset, " failed:", GetLastError());
			return 0;
		}
		return (LONGLONG)read_size;
	}
	LONGLONG BackupFSCore::Read(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset)
	{
		std::lock_guard<std::mutex> locker(_Locker);
		//if the mode is drill or incremental and the offset is less than base file size
		//read the data from the base file or incremental file
		if (_Mode != FILE_SYSTEM_MODE::NORMAL_MODE && offset < _BaseFileSize)
		{
			return ReadForIncremental(buffer, bufferlength, offset);
		}
		//read the data from the incremental data file
		return ReadNormal(buffer, bufferlength, offset);		
	}
	std::shared_ptr<DATA_BLOCK> BackupFSCore::GetNewDataBlock(LONGLONG offset,LONGLONG length)
	{
		// at least 4K
		LONGLONG allocate_size = ROUND_UP_PAGES(length) * BACKUPFS_PAGE_SIZE;
		// if offset is not aligned 4K,then need extra size for the length
		if (offset % BACKUPFS_PAGE_SIZE != 0)
		{
			LONGLONG not_aligned_size = (BACKUPFS_PAGE_SIZE - offset % BACKUPFS_PAGE_SIZE);
			if (length > not_aligned_size)
			{
				allocate_size = ROUND_UP_PAGES(length - not_aligned_size) * BACKUPFS_PAGE_SIZE ;
				// add the not aligned size
				allocate_size += BACKUPFS_PAGE_SIZE;
			}
			else
			{
				//only need one page
				allocate_size = BACKUPFS_PAGE_SIZE;
			}
		}
		std::shared_ptr<DATA_BLOCK> block = std::make_shared<DATA_BLOCK>();
		block->OffsetInFile = offset / BACKUPFS_PAGE_SIZE * BACKUPFS_PAGE_SIZE;
		block->OffsetInData = _CurrentDataFileOffset.fetch_add(allocate_size);
		block->Length = allocate_size;
		block->Attr = DATA_ATTR::NONE_ATTR;
		block->Id = BackupFSCore::DataBlockId++;
		std::lock_guard<std::mutex> locker(_Locker);
		BackupFSSql::UpdateCurrentUsedSize(GetDb(), AddUsedSize(allocate_size));		
		return block;
	}
	/*
	Update the bitmap of the incremental session
	*/
	bool BackupFSCore::_UpdateIncrementalBitmap(LONGLONG offset, LONGLONG length)
	{
		if (_Mode == FILE_SYSTEM_MODE::NORMAL_MODE)
		{
			return true;
		}
		LONGLONG group_index = offset / BACKUPFS_BITMAP_GROUP_SIZE;
		//if the mode is drill or incremental,need update the bitmap info
		if (_IncrementalBitmap.find(group_index) == _IncrementalBitmap.end())
		{
			bool SaveToFile = _Mode == FILE_SYSTEM_MODE::INCREMENTAL_MODE;
			std::shared_ptr<BackupFSBitmap> bitmap = std::make_shared<BackupFSBitmap>(_DataPath, SaveToFile,group_index);
			_IncrementalBitmap[group_index] = bitmap;
			bitmap->Set(offset % BACKUPFS_BITMAP_GROUP_SIZE, length);
			// if the bitmap file not been opended,open it.
			if (_HandleBitmap == INVALID_HANDLE_VALUE)
			{
				_HandleBitmap = CreateFile(_BitmapFile.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);
				if (_HandleBitmap == INVALID_HANDLE_VALUE)
				{
					Logger->Error("Create Bitmap file failed,the error is ", GetLastError());
					return false;
				}
			}
			if (_HandleBitmap != INVALID_HANDLE_VALUE)
			{
				DWORD written_size = 0;
				if (!WriteFile(_HandleBitmap, &group_index, sizeof(group_index), &written_size, NULL))
				{
					Logger->Error("Write Bitmap file failed,the error is ", GetLastError());
					return false;
				}
			}
		}
		else
		{
			_IncrementalBitmap[group_index]->Set(offset % BACKUPFS_BITMAP_GROUP_SIZE, length);
		}
		return true;
	}
	LONGLONG BackupFSCore::WriteForIncremental(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset)
	{
		LONGLONG group_index = offset / BACKUPFS_BITMAP_GROUP_SIZE;
		LONGLONG group_index2 = (offset + number_of_bytes_to_write) / BACKUPFS_BITMAP_GROUP_SIZE;
		LONGLONG total_length = number_of_bytes_to_write;
		LONGLONG group_offset = offset;
		LONGLONG total_written_size = 0;
		//group by group
		for (LONGLONG idx = group_index; idx <= group_index2; idx++)
		{
			LONGLONG group_length = total_length;
			//beyond the group,adjust the group_length
			//check the group_length and offset whether exceed the group bound
			if ((total_length + group_offset) > (idx +1)* BACKUPFS_BITMAP_GROUP_SIZE)
			{
				group_length = (idx + 1) * BACKUPFS_BITMAP_GROUP_SIZE - group_offset;
			}
			//Divide the blocks by length, each block is 4K, 
			//the first and last blocks may be less than 4K
			LONGLONG written_size = 0;
			for (; written_size < group_length;)
			{
				bool is_in_bitmap = false;
				if (_IncrementalBitmap.find(idx) != _IncrementalBitmap.end())
				{
					auto bitmap = _IncrementalBitmap[idx];
					if (bitmap->IsSet(group_offset % BACKUPFS_BITMAP_GROUP_SIZE))
					{
						is_in_bitmap = true;
					}
				}
				LONGLONG need_write_size = BACKUPFS_PAGE_SIZE;
				//block_offset means the offset in the data file
				LONGLONG block_offset = group_offset / BACKUPFS_PAGE_SIZE * BACKUPFS_PAGE_SIZE;
				if (group_offset % BACKUPFS_PAGE_SIZE != 0)
				{
					need_write_size = BACKUPFS_PAGE_SIZE - group_offset % BACKUPFS_PAGE_SIZE;
				}
				if (need_write_size > group_length - written_size)
				{
					need_write_size = group_length - written_size;
				}
				LONGLONG temp_write_size = 0;
				if (!is_in_bitmap)
				{
					//copy the original 4K data first
					if (need_write_size < BACKUPFS_PAGE_SIZE)
					{
						char temp_buffer[BACKUPFS_PAGE_SIZE] = { 0 };
						LONGLONG read_size = 0;
						//read the data from the base data file
						if (!BackupFSUtils::ReadFileData(_HandleBaseDataFile, temp_buffer, block_offset, BACKUPFS_PAGE_SIZE, read_size))
						{
							Logger->Error("read file from base data file failed:", GetLastError());
							return 0;
						}
						//write to the data file
						if (!BackupFSUtils::WriteFileData(_HandleDataFile, temp_buffer, block_offset, BACKUPFS_PAGE_SIZE, read_size))
						{
							Logger->Error("write file to data failed:", GetLastError());
							return 0;
						}
					}
				}
				//write the request data
				if (!BackupFSUtils::WriteFileData(_HandleDataFile, (char*)buffer + total_written_size, group_offset, need_write_size, temp_write_size))
				{
					Logger->Error("write file to data failed:", GetLastError());
					return 0;
				}
				//update the bitmap
				_UpdateIncrementalBitmap(block_offset, BACKUPFS_PAGE_SIZE);

				written_size += temp_write_size;
				total_written_size += temp_write_size;
				group_offset += temp_write_size;
				total_length -= temp_write_size;
			}

		}
		return total_written_size;

	}
	LONGLONG BackupFSCore::WriteNormal(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset)
	{
		if (_ReadOnly)
		{
			return 0;
		}
		if (!BackupFSUtils::Seek(_HandleDataFile, offset))
		{
			return 0;
		}
		//
		DWORD written_size = 0;
		if (!WriteFile(_HandleDataFile, buffer, (DWORD)number_of_bytes_to_write, &written_size, NULL))
		{
			Logger->Error("write file to pos ", offset, " failed:", GetLastError());
			return 0;
		}
		_UpdateIncrementalBitmap(offset, number_of_bytes_to_write);
		return (LONGLONG)written_size;
	}
	LONGLONG BackupFSCore::Write(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset)
	{
		std::lock_guard<std::mutex> locker(_Locker);
		/*
		If the mode is drill or incremental,and the offset is less than the base file size
		write to the base file or incremental data file
		*/
		if (_Mode != FILE_SYSTEM_MODE::NORMAL_MODE && offset < _BaseFileSize)
		{
			return WriteForIncremental(buffer, number_of_bytes_to_write, offset);
		}
		//write to the incremental data file
		return WriteNormal(buffer, number_of_bytes_to_write, offset);
	}
	void BackupFSCore::RemoveFileBlocks(const std::list<std::shared_ptr<DATA_BLOCK>>& blocks)
	{
		std::lock_guard<std::mutex> locker(_Locker);
		for (auto &block : blocks)
		{
			_SetSparseRange(_HandleDataFile, block->OffsetInData, block->Length);
		}
	}
	void BackupFSCore::StopFS()
	{
		if (_HandleDataFile != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_HandleDataFile);
			_HandleDataFile = INVALID_HANDLE_VALUE;
		}
		if (_HandleFlag != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_HandleFlag);
			_HandleFlag = INVALID_HANDLE_VALUE;
		}
		if (_HandleBaseDataFile != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_HandleBaseDataFile);
			_HandleBaseDataFile = INVALID_HANDLE_VALUE;
		}
		if (_HandleBitmap != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_HandleBitmap);
			_HandleBitmap = INVALID_HANDLE_VALUE;
		}
		if (fs::exists(_FlagFile))
		{
			fs::remove(_FlagFile);
		}
		/*
		For the drill mode, remove the temp files
		*/
		if (_Mode == FILE_SYSTEM_MODE::DRILL_MODE)
		{
			if (std::filesystem::exists(_DataFile))
			{
				std::filesystem::remove(_DataFile);
			}
			if (std::filesystem::exists(_DbFile))
			{
				std::filesystem::remove(_DbFile);
			}
		}
		_IncrementalBitmap.clear();
		Logger->Info("Stop FS from Core");
	}
	bool BackupFSCore::_OpenCoreFiles()
	{
		//_DataPath exist
		if (!fs::exists(_DataPath))
		{
			if (!fs::create_directories(_DataPath))
			{
				Logger->Error("Can't Create the folder ", W2S(_DataPath), " The error is ", GetLastError());
				return false;
			}
		}
		//create the flag file
		if (fs::exists(_FlagFile))
		{
			Logger->Warn("The BackupFS file system was not correctly umounted last time, which may cause data loss");
		}
		else
		{
			_HandleFlag = CreateFile(_FlagFile.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
				FILE_ATTRIBUTE_NORMAL, NULL);
			if (_HandleFlag == INVALID_HANDLE_VALUE)
			{
				Logger->Error("Create Flag file failed,the error is ", GetLastError());
				return false;
			}
		}
		bool inc_mode = false;
		if (_Mode == FILE_SYSTEM_MODE::INCREMENTAL_MODE && std::filesystem::exists(_DataFile))
		{
			inc_mode = true;
		}
		bool data_file_exist = std::filesystem::exists(_DataFile);
		DWORD dwCreationDisposition = OPEN_ALWAYS;
		_HandleDataFile = CreateFile(_DataFile.c_str(),
			GENERIC_READ| GENERIC_WRITE,
			0,
			NULL,
			dwCreationDisposition,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if (_HandleDataFile == INVALID_HANDLE_VALUE)
		{
			Logger->Error("Can't open the data file ", W2S(_DataFile), ", Error is ", GetLastError());
			return false;
		}
		if (!data_file_exist)
		{
			DWORD dwTemp;
			if (!DeviceIoControl(_HandleDataFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL))
			{
				CloseHandle(_HandleDataFile);
				Logger->Error("Set sparse failed,", GetLastError());
				return false;
			}
		}
		LONGLONG file_size = filesystem::file_size(_DataFile);
		if (file_size < sizeof(_FileHeader))
		{
			DWORD written_size = 0;
			if (!WriteFile(_HandleDataFile, &_FileHeader, sizeof(_FileHeader), &written_size, NULL))
			{
				Logger->Error("Write data file failed:", GetLastError());
				return false;
			}
			file_size = BACKUPFS_PAGE_SIZE;
		}
		else
		{
			DWORD read_size = 0;
			if (!ReadFile(_HandleDataFile, &_FileHeader, sizeof(_FileHeader), &read_size, NULL))
			{
				Logger->Error("Read data file failed:", GetLastError());
				return false;
			}
			//check the magic
			if (memcmp(BACKUPFS_MAGIC, _FileHeader.Magic, strlen(BACKUPFS_MAGIC)) != 0)
			{
				Logger->Error("Check BackupFS Magic failed, the magic is ", _FileHeader.Magic);
				return false;
			}
		}
		_CurrentDataFileOffset = ROUND_UP_PAGES(file_size) * BACKUPFS_PAGE_SIZE;
		if (_Mode != FILE_SYSTEM_MODE::NORMAL_MODE)
		{
			file_size = filesystem::file_size(_BaseDataFile);
			_CurrentDataFileOffset = ROUND_UP_PAGES(file_size) * BACKUPFS_PAGE_SIZE;

			_BaseFileSize = _CurrentDataFileOffset;
			_HandleBaseDataFile = CreateFile(_BaseDataFile.c_str(),
				GENERIC_READ,
				0,
				NULL,
				dwCreationDisposition,
				FILE_ATTRIBUTE_NORMAL,
				NULL);
			std::string mode_str = "DRILL";
			if (_Mode == FILE_SYSTEM_MODE::INCREMENTAL_MODE)
			{
				mode_str = "INCREMENTAL";
			}
			Logger->Info("Start ", mode_str," mode, the base data file size is ", _BaseFileSize);
		}
		Logger->Info("The BackupFS version is ", _FileHeader.Version, ",Current offset is ",_CurrentDataFileOffset,",Data offset is ", _FileHeader.DataOffset, ", Block size is ", _FileHeader.BlockSize);
		
		return true;
	}
}